home *** CD-ROM | disk | FTP | other *** search
- /*
- * Dos direct-disk I/O routines for PDTAR
- * By E. Roskos 2/88
- * For Minix-compatible multivolume tar implementation under DOS
- *
- * These routines are based on my Minix "build" I/O code, although
- * changed a lot...
- */
-
- #ifdef MSDOS
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <dos.h>
-
- extern int physdrv;
- extern int devsize;
- extern int ftty;
- static long curblk = 0;
- static int inited = 0;
-
- /*
- * Local I/O buffers. We do the actual disk I/O to one of these two.
- * The reason is that we select which one we'll use, and set iobuf to
- * point to it, in order to get a block of memory that doesn't cross
- * a 64K boundary -- because the DMA controller can't do I/O across
- * a 64K boundary.
- */
- static char buf1[512], buf2[512];
- static char *iobuf;
-
- /*
- * DMAoverrun checks whether buff1 crosses a 64K boundary.
- */
- static int
- DMAoverrun(buff1)
- char *buff1;
- {
- int i;
-
- i = (int)buff1;
- return(i > i + 512);
- }
-
- /*
- * absio does absolute disk I/O, using the ROM BIOS
- * It performs BIOS operation "fn", on "drive", specifying
- * block number "blocknr" and buffer "buff" (which must
- * be in the single (small-model) data segment).
- * Note that the block numbering scheme corresponds to the
- * Minix, PC/IX, and DOS 2.x block numbering, not the DOS
- * 3.x block numbering.
- */
- static int
- absio(fn, drive, blocknr, buff)
- int fn;
- int drive;
- long blocknr;
- char *buff;
- {
- union REGS iregs;
- union REGS oregs;
- int track;
-
- iregs.h.ah = fn;
- iregs.h.dl = drive;
- track = blocknr / 9;
- iregs.h.dh = track & 1;
- iregs.h.ch = track >> 1;
- iregs.h.cl = (blocknr % 9) + 1;
- iregs.h.al = 1;
- iregs.x.bx = (int)buff;
-
- int86(0x13, &iregs, &oregs);
-
- if (oregs.x.cflag)
- {
- #ifdef DEBUGIO
- fprintf(stderr, "absio: error %sing drv %c block %d address %x: bios code %x\n",
- fn==2? "read" : "writ", 'A'+drive, blocknr, buff, oregs.h.ah&0xff);
- #endif /* DEBUGIO */
- return(oregs.h.ah&0xff);
- }
- else
- {
- return(0);
- }
- }
-
- /*
- * initdiskio initializes the floppy disk subsystem and selects
- * a local buffer for us to use, if this is the first time it is
- * called. Otherwise, it does nothing.
- */
- static void
- initdskio()
- {
- if (!inited)
- {
- absio(0, 0, 0, 0);
- if (DMAoverrun(buf1))
- iobuf = buf2;
- else
- iobuf = buf1;
- inited++;
- }
- }
-
- /*
- * absread performs an absolute disk read of "drive"'s block
- * "blocknr", reading into the buffer at "buff".
- */
- static int
- absread(drive, blocknr, buff)
- int drive;
- long blocknr;
- char *buff;
- {
- int err;
-
- initdskio();
- err = absio(2, drive, blocknr, iobuf);
- if (!err)
- memcpy(buff, iobuf, 512);
- return(err);
- }
-
- /*
- * abswrite performs an absolute disk write of "drive"'s block
- * "blocknr", reading into the buffer at "buff".
- */
- static int
- abswrite(drive, blocknr, buff)
- int drive;
- long blocknr;
- char *buff;
- {
- int err;
-
- initdskio();
- memcpy(iobuf, buff, 512);
- return(absio(3, drive, blocknr, iobuf));
- }
-
- /*
- * physrw reads or writes the data at "buf" for length "len", which
- * must be a multiple of 512 bytes; it reads if fread is 1, or writes
- * if fread is 0. The data is read/written on the next consecutive
- * block of the floppy disk; if the end of the disk has been reached
- * (as determined by the disk size block count in the global variable
- * devsize) it asks the user to change disks before it performs the I/O,
- * then performs the I/O to block 0 of the new disk.
- */
- static int
- physrw(buf, len, fread)
- char *buf;
- int len;
- int fread;
- {
- int err;
- int errct = 0;
- int nbytes;
- static void diskerr();
-
- nbytes = len; /* save for return value */
-
- /* be sure size of xfer is a multiple of DOS physical block size */
- if (len & 0x1ff)
- {
- fprintf(stderr, "tar: fatal error: phys disk I/O must be ");
- fprintf(stderr, "multiple of 512 bytes\n");
- exit(1);
- }
-
- /* convert byte count to DOS block count */
- len >>= 9;
-
- /* now read or write a block at a time into the buffer */
- while (len > 0)
- {
- /* check for time to change disks */
- if (curblk >= devsize)
- {
- uprintf(ftty, "\ntar: Change disks and press [Enter]: ");
- while (ugetc(ftty)!='\n') ;
- curblk = 0;
- }
-
- /* read or write the next block */
- if (fread)
- err = absread(physdrv, curblk, buf);
- else
- err = abswrite(physdrv, curblk, buf);
-
- /* check for an error */
- if (err)
- {
- diskerr(fread? "reading" : "writing",
- physdrv, curblk, err);
- errct++;
- }
- /* increment block number & buf addr, decrement count */
- curblk++;
- buf += 512;
- len--;
- }
- if (errct)
- return(-1);
- else
- return(nbytes);
- }
-
- /*
- * physwrite is the "write" version of physrw, and is what is called
- * from outside this package. It writes the data at "buf" for
- * length "len", which must be a multiple of 512 bytes, as described
- * above under "physrw".
- */
- int
- physwrite(buf, len)
- char *buf;
- int len;
- {
- return(physrw(buf, len, 0));
- }
-
- /*
- * see comments for physwrite
- */
- int
- physread(buf, len)
- char *buf;
- int len;
- {
- return(physrw(buf, len, 1));
- }
-
- /*
- * This routine prints an error message for disk I/O: the operation
- * ("reading", "writing") is in s, the drive number in "drive",
- * the sector number in "sectnum", and the BIOS AH return code
- * is in "err".
- */
- static void
- diskerr(s,drive,sectnum,err)
- int sectnum, err,drive;
- char *s;
- {
- extern char *derrtab[];
- char *mp;
- fprintf(stderr, "Error %s drive %c, sector: %d, code: %d = '",
- s, drive+'A',sectnum, err);
- switch (err)
- {
- case 0:
- mp = "No error";
- break;
- case 1:
- mp = "Bad command passed to BIOS";
- break;
- case 2:
- mp = "Address mark not found";
- break;
- case 3:
- mp = "Disk is write protected";
- break;
- case 4:
- mp = "Sector not found";
- break;
- case 8:
- mp = "DMA overrun";
- break;
- case 9:
- mp = "DMA crosses 64K boundary (internal error)";
- break;
- case 0x10:
- mp = "Bad CRC on disk read";
- break;
- case 0x20:
- mp = "Disk controller has failed";
- break;
- case 0x40:
- mp = "Seek failed";
- break;
- case 0x80:
- mp = "No response from controller";
- break;
- default:
- mp = "Unknown error";
- break;
- }
- fprintf(stderr,"%s'\n", mp);
- }
-
- #endif /* MSDOS */
-